#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define N 20

void ClearScreen()
{
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {0, 0};
    DWORD cCharsWritten;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    DWORD dwConSize;

    // 获取控制台缓冲区大小
    GetConsoleScreenBufferInfo(hConsole, &csbi);
    dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

    // 用空格填充整个屏幕
    FillConsoleOutputCharacter(hConsole, ' ', dwConSize, coordScreen, &cCharsWritten);

    // 重置光标位置到左上角
    SetConsoleCursorPosition(hConsole, coordScreen);
}

void Mapprint(char Map[N][N])
{
	//上边界
	for(int i = 0; i < 2*N+2; i++)
	    printf("-");
	printf("\n");
	//打印地图
    for(int i = 0; i < N; i++)
	{
		//左边界
		printf("|");
		for(int j = 0; j < N; j++)
		{
			printf("%c ",Map[i][j]);
		}
		//右边界
		printf("|");
		printf("\n");
	}
	//下边界
	for(int i = 0; i < 2*N+2; i++)
	    printf("-");
	printf("\n");
}

int main()
{
    //定义并清洗地图
    char Map[N][N];
    for(int i = 0; i < N; i++)
	{
		for(int j = 0; j < N; j++)
		{
			Map[i][j] = ' ';
		}
	}
    //定义蛇的长度及所有部位的坐标
    int length = 3, snake[N*N][2];
	//定义初始蛇各个部位的坐标
    snake[0][0] = N/2; snake[0][1] = N/2;
    snake[1][0] = N/2 + 1; snake[1][1] = N/2;
    snake[2][0] = N/2 + 2; snake[2][1] = N/2;
    //定义食物的坐标
    int x, y, direction = 1;
    //随机生成食物
    srand(time(NULL));
    x = rand() % N;
    y = rand() % N;
    Map[x][y] = 'O';
    //划归蛇的位置
	Map[snake[0][0]][snake[0][1]] = '@';
	Map[snake[1][0]][snake[1][1]] = '*';
	Map[snake[2][0]][snake[2][1]] = '*';
    //打印地图
	Mapprint(Map);
    printf("2s后开始");
    Sleep(2000);
    while (1)
	{
        // 清屏
        ClearScreen();
        //蛇的变化：将尾巴置为空格，所有部位向前移动一个，覆盖掉原本头的位置
		//保存蛇尾的位置，便于失败后恢复蛇尾以及增加长度
        Map[snake[length-1][0]][snake[length-1][1]] = ' ';
		int tail[2] = {snake[length-1][0], snake[length-1][1]};
        for(int i = length-1; i > 0; i--)
		{
			snake[i][0] = snake[i-1][0];
			snake[i][1] = snake[i-1][1];
		}
        //根据存储的方向确定头的下一个位置
        switch (direction)
        {
        case 1:
            snake[0][0]--;
            break;
        case 2:
            snake[0][1]--;
            break;
        case 3:
            snake[0][0]++;
            break;
        case 4:
            snake[0][1]++;
            break;
        default:
            break;
        }
        //边界限制
        if(snake[0][0] < 0 || snake[0][0] >= N || snake[0][1] < 0 || snake[0][1] >= N || Map[snake[0][0]][snake[0][1]] == '*')
		{
			//恢复蛇尾并打印地图
			Map[tail[0]][tail[1]] = '*';
			Mapprint(Map);
            break;
		}
        //检测是否吃到食物
        if (Map[snake[0][0]][snake[0][1]] == 'O')
		{
            //吃到食物后增加蛇的长度，增加的部分即原来的蛇尾
            length++;
            Map[tail[0]][tail[1]] = '*';
            snake[length-1][0] = tail[0]; snake[length-1][1] = tail[1];
			//确保食物的生成合法
			while(1)
			{
				x = rand() % N;
				y = rand() % N;
				if(Map[x][y] == ' ')
				{
					Map[x][y] = 'O';
					break;
				}
			}
		}
		//重新划归蛇的位置,划归下一个蛇头，以及将接替蛇头的位置的蛇头划归为蛇身
    	Map[snake[0][0]][snake[0][1]] = '@';
		Map[snake[1][0]][snake[1][1]] = '*';
		//打印地图
        Mapprint(Map);
        // 检测WASD键状态
        short state = GetAsyncKeyState('W');
        if (state & 0x8000)
		{
            direction = 1;
        }
        state = GetAsyncKeyState('A');
        if (state & 0x8000)
		{
            direction = 2;
        }
		state = GetAsyncKeyState('S');
        if (state & 0x8000)
		{
            direction = 3;
        }
		state = GetAsyncKeyState('D');
        if (state & 0x8000)
		{
            direction = 4;
        }
        // 检测F1键状态
        state = GetAsyncKeyState(VK_F1);
        if (state & 0x8000)
		{
            break;
        }
        Sleep(50); // 暂停50毫秒
    }
    printf("程序结束\n");
    return 0;
}
